package com.minilcu;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.minilcu.exception.EngineException;
import com.minilcu.exception.ExecCallerException;
import com.minilcu.tools.LcuEngineTool;
/**
 * @author tangyj
 * */
public class LcuEngine implements LcuEngineInterface {
	
	private static Logger log = Logger.getLogger(LcuEngine.class);
	
	private Map inParam;
	private Map outParam;
	private String filePath = "process.properties";	//存放配置流程名子与配置文件对应的路径，默认存放在src下
	
	@SuppressWarnings("unchecked")
	public void startEgnine(String processName,Map inParamMap,Map outParamMap) throws ExecCallerException{
		log.info("开始处理流程："+processName);
		this.inParam = inParamMap;
		this.outParam = outParamMap;
		String fileName = LcuEngineTool.getFileName(filePath, processName);
		int callerFlag = 0;	//方法调用标记，方法调用caller、子流程后置为1，数据解析buffer后置为0，开始也为0。
		SAXReader saxReader = new SAXReader();
		File file = new File(fileName);
		/*FileInputStream in = null;
		try {
			in = new FileInputStream(file);
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		try {
			Reader reader = new InputStreamReader(in,"UTF-8");
		} catch (UnsupportedEncodingException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}*/

		Document doc = null;
		try {
			doc = saxReader.read(file);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Element rootEle = doc.getRootElement();
		Element startEle = rootEle.element("start-state");
		
		String nextEle;	//要转向下一个结点的名子
		Node nextNode;	//下一个要执行的结点
		String nodeName;	//下一个结点名子
		nextEle = startEle.element("trasition").attributeValue("to");
		log.info("下一个要执行结点名子："+nextEle);
		//进行循环直到结束结点state-end
		do{
			//用xPath进行查找
			String xPathStr = "/process/*[@name='"+nextEle+"']";			
			nextNode = doc.selectSingleNode(xPathStr);
			nodeName = nextNode.getName();
			log.info("当前结点类型："+nodeName);
			if(nodeName.equals("end-state")){
				log.info("结束处理流程："+processName);
				break;
			}else if(nodeName.equals("decision")){
				Element delegationEle = (Element)nextNode.selectSingleNode("delegation");
				List<Element> trasitionList = delegationEle.elements("trasition");
				Map deParam = null;
				if(callerFlag==0){
					deParam = inParam;
				}else{
					deParam = outParam;
				}
				nextEle = LcuEngineTool.decision(trasitionList,deParam);
				log.info("下一个要执行结点名子："+nextEle);
			}else if(nodeName.equals("state")){
				Element actionEle = (Element)nextNode.selectSingleNode("action");
				String type = actionEle.attributeValue("type");
				if(type.equals("caller")){//调用java方法
					String classStr = actionEle.attributeValue("class");
					String methodStr = actionEle.attributeValue("method");
					log.info("执行"+classStr+"."+methodStr);
					if(callerFlag==1){
						this.inParam = outParam;
					}
					String errorInfo = LcuEngineTool.exeMethod(classStr,methodStr,inParam,outParam);
					callerFlag = 1;
					if(!errorInfo.equals("0000")){//调用方法不出错返回0000
						throw new ExecCallerException("执行:"+classStr+"中"+methodStr+"方法异常");
					}
					log.info("错误信息："+errorInfo);
				}else if(type.equals("buffer")){//数据解析存入下一结点入参
					String bufferStr = actionEle.getTextTrim();
					log.info("buffer:"+bufferStr);
					if(callerFlag==1){
						this.inParam = outParam;
					}
					LcuEngineTool.bufferData(bufferStr,inParam);
					callerFlag =0;
				}else{//结点类型没定义，要报错
					log.error("action结点没有该属性类型值："+type);
					try {
						throw new EngineException("action结点没有该属性类型值："+type);
					} catch (EngineException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
				Element trasEle = (Element)nextNode.selectSingleNode("trasition");
				nextEle = trasEle.attributeValue("to");
				log.info("下一个要执行结点名子："+nextEle);
			}else if(nodeName.equals("process-state")){//调用子流程
				Element psEle = (Element)nextNode.clone();
				String subProcessName = psEle.attributeValue("name");
				log.info("开始调用子流程："+subProcessName);
				if(callerFlag==1){
					this.inParam = outParam;
				}

				this.startEgnine(subProcessName, inParam, outParam);
				log.info("结束调用子流程："+subProcessName);
				callerFlag = 1;
				
				Element trasEle1 = (Element)nextNode.selectSingleNode("trasition");
				nextEle = trasEle1.attributeValue("to").trim();
				log.info("下一个要执行结点名子："+nextEle);
			}else{
				log.error("不存在"+nodeName+"类型结点");
				try {
					throw new EngineException("不存在"+nodeName+"类型结点");
				} catch (EngineException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}while(true);
	}

	public void setFilePath(String filePath) {
		this.filePath = filePath;
	}

}